#include "cpu_info.h"
#include "memory_info.h"
#include "disk_info.h"
#include "net_infom.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "console_ctrl.h"
#include "math.h"

int demo() {
    printf("%s\n", COMPLATE_MESSAGE);

    // memory
    struct MemoryInfo minfo;
    if (GetMemoryInfo(&minfo) != 0) {
        printf("GetMemoryInfo fail\n");
    } else {
        printf("mem_total: %d, mem_free: %d, mem_avalible: %d, mem_buffers: %d, mem_cached: %d\nswap_total: %d, swap_free: %d\n", 
        minfo.mem_total, minfo.mem_free, minfo.mem_avalible, minfo.mem_buffers, minfo.mem_cached, minfo.swap_total, minfo.swap_free);
    }
    
    // disk
    int num = GetMountedOnListNumber();
    if (num<=0) {
        printf("GetMountedOnListNumber fail\n");
    } else {
        for (int i=0;i<num;i++) {
            struct statfs sfs;
            char mounted[256];
            if (GetMountedOnList(i+1, mounted) != 0) {
                printf("GetMountedOnList fail %d\n", i);
                break;
            }
            if (GetDiskInfo(mounted, &sfs) != 0) {
                printf("GetDiskInfo fail\n");
            } else {
                printf("name: %s, f_type: %d, f_bsize: %d, f_blocks: %ld, f_bfree: %ld, f_bavail: %lu\n", mounted, sfs.f_type, sfs.f_bsize, sfs.f_blocks, sfs.f_bfree, sfs.f_bavail);
            }
        }
    }

    // net speed
    struct NetInfo net_info;
    if (NetInfoInit(&net_info, IFF_UP | IFF_RUNNING) == -1) {
        printf("NetInfoInit fail\n");
        return -1;
    }
    for (int i=0; i<net_info.net_info_num; i++) {
        printf("%s : %s\n", net_info.ninfo[i].name, net_info.ninfo[i].ip);
    }
    for (int i=0; i<100; i++) {
        if (GetNetSpeed(&net_info, 1000) != 0) {
            printf("GetNetSpeed fail\n");
        } else {
            for (int j=0; j<net_info.net_info_num; j++) {
                if (net_info.ninfo[j].sa_family == AF_INET) 
                    printf("%s : rx==%ldB/s, tx==%ldB/s\n", net_info.ninfo[j].name, net_info.ninfo[j].flow_info.rcv_speed, net_info.ninfo[j].flow_info.tx_speed);
            }
            printf("\n");
        }
        sleep(1);
    }
    NetInfoDeinit(&net_info);
    
    // io
    struct IoStatusInfo io_rate;
    if (IOUsageRateInit(&io_rate) == -1) {
        printf("IOUsageRateInit fail\n");
        return -1;
    }
    for (size_t i = 0; i < 100; i++)
    {
        if (GetIOUsageRate(&io_rate, 1000) != -1) {
            for (int j=0; j<io_rate.disk_num; j++) {
                printf("%s: %1.2f%%  ", io_rate.nstatus[j].device_name, io_rate.io_usage_rate[j]);
            }
            printf("\n");
            // printf("\r\033[A\033[K");
        } else {
            printf("GetIOUsageRate fail\n");
        }
        sleep(1);
    }
    IOUsageRateDeinit(&io_rate);

    // cpu
    struct CpuUsageRate usage_rate;
    if (CpuUsageRateInit(&usage_rate) == -1) {
        printf("CpuUsageRateInit fail\n");
        return -1;
    }
    for (size_t i = 0; i < 100; i++)
    {
        if (GetCpuUsageRate(&usage_rate) != -1) {
            for (int j=0;j<usage_rate.cpu_num;j++) {
                printf("%s: %1.2f%% ", usage_rate.ninfo[j].name, usage_rate.cpu_usage_rate[j]);
            }
            printf("\n");
            printf("\r\033[A\033[K");
        } else {
            printf("GetCpuUsageRate fail\n");
        }
        sleep(1);
    }
    CpuUsageRateDeinit(&usage_rate);

    return 0;
}



/*  designed 
1. 
cpu:   [======================]100%
cpu0:  [=====                 ]10%
cpu99: [============          ]50%
2. 
[Memory]
total      100.33GB
used        80.44GB
avail           20B
swap_total 100.33GB
swap_free   80.44GB

3. 
[Disk]
Mount      Used   Avail  Use%
/dev/sda1  55.1G  30.2K  98.2%
(最短需要10字节)

4. 
[io]
Name  Use%    w/s      r/s
sda1  10.11%  322.89K  322.89K
(最短需要10字节)

5.
[Net]
Interface  Ip               tx/s     rx/s     
eth0       192.168.100.123  524.36K  524.36K
*/

/*  designed simple
cpu:   [======================]100%
cpu0:  [=====                 ]10%
cpu99: [============          ]50%
memory:[====                  ]111.3G/100.2G (不包含swap)
disk:  [===========           ]110.4G/20.3G  (只显示总空间最大一个)
io:    [=                     ]1%
[Net]
Interface  Ip               tx/s     rx/s     
eth0       192.168.100.123  524.36K  524.36K
*/
struct MemoryInfo minfo;
struct NetInfo net_info;
struct IoStatusInfo io_rate;
struct CpuUsageRate cpu_rate;
char disk_mounted[256] = {0};
struct statfs disk_sfs;
int init() {
    if (NetInfoInit(&net_info, IFF_UP | IFF_RUNNING) == -1) {
        printf("NetInfoInit fail\n");
        return -1;
    }
    if (IOUsageRateInit(&io_rate) == -1) {
        printf("IOUsageRateInit fail\n");
        return -1;
    }
    if (CpuUsageRateInit(&cpu_rate) == -1) {
        printf("CpuUsageRateInit fail\n");
        return -1;
    }
    long big_disk=0;
    int num = GetMountedOnListNumber();
    if (num<=0) {
        printf("GetMountedOnListNumber fail\n");
    } else {
        for (int i=0;i<num;i++) {
            char mounted[256];
            if (GetMountedOnList(i+1, mounted) != 0) {
                printf("GetMountedOnList fail %d\n", i);
                return -1;
            }
            if (GetDiskInfo(mounted, &disk_sfs) != 0) {
                printf("GetDiskInfo fail: %s\n", mounted);
            } else {
                if (big_disk < disk_sfs.f_blocks) {
                    big_disk = disk_sfs.f_blocks;
                    strcpy(disk_mounted, mounted);
                    printf("disk : %s,%ld,%d\n", disk_mounted, disk_sfs.f_blocks, disk_sfs.f_bsize);
                }
                // printf("name: %s, f_type: %d, f_bsize: %d, f_blocks: %ld, f_bfree: %ld, f_bavail: %lu\n", mounted, sfs.f_type, sfs.f_bsize, sfs.f_blocks, sfs.f_bfree, sfs.f_bavail);
            }
            
        }
    }
    return 0;
}

int reflesh(int time_ms) {
    // mem
    if (GetMemoryInfo(&minfo) != 0) {
        printf("GetMemoryInfo fail\n");
    }
    // disk
    if (disk_mounted[0] && (GetDiskInfo(disk_mounted, &disk_sfs) != 0)) {
        printf("GetDiskInfo fail\n");
    }
    // net 
    if (GetNetSpeed(&net_info, time_ms) != 0) {
        printf("GetNetSpeed fail\n");
    }
    // io
    if (GetIOUsageRate(&io_rate, time_ms) == -1) {
        printf("GetIOUsageRate fail\n");
    }
    // cpu
    if (GetCpuUsageRate(&cpu_rate) == -1) {
        printf("GetCpuUsageRate fail\n");
    }
    return 0;
}

void show_cpu_formate(char *name, int max_name, float progress, int progress_len, int temperature) {
    char format_buff[50];
    char arr[1024] = {0};
    if (isnan(progress)) progress = 0;
    int tmp = progress_len*progress/100;
    
    memset(arr, '=', tmp>progress_len?progress_len:tmp);

    CursorMoveToLeftBeginAndClearAfter();
    if (strlen(name) < max_name) {
        sprintf(format_buff, "%%-%ds[%%-%ds][%1.2f%%%%,%1.1f°C]\n", max_name, progress_len, progress, temperature/1000.0);
        printf(format_buff, name, arr);
    } else {
        sprintf(format_buff, "%.*s[%%-%ds][%1.2f%%%%,%1.1f°C]\n", max_name, name, progress_len, progress, temperature/1000.0);
        printf(format_buff, arr);
    }
}

void show_disk_formate(char *name, int max_name, long long max_num, long long min_num, int progress_len) {
    char format_buff[50];
    char arr[1024] = {0};
    char *max_unit, *min_unit;
    double f_max_num, f_min_num;
    int tmp = progress_len*min_num*100/max_num/100;
    memset(arr, '=', tmp>progress_len?progress_len:tmp);
    if (max_num<1024) {
        max_unit = "B";
        f_max_num = max_num;
    } else if (max_num/1024 < 1024) {
        max_unit = "KB";
        f_max_num = max_num/1024.0;
    } else if (max_num/1024/1024 < 1024) {
        max_unit = "MB";
        f_max_num = max_num/1024.0/1024;
    } else if (max_num/1024/1024/1024 < 1024) {
        max_unit = "GB";
        f_max_num = max_num/1024.0/1024/1024;
    } else {
        max_unit = "TB";
        f_max_num = max_num/1024.0/1024/1024/1024;
    }
    if (min_num<1024) {
        min_unit = "B";
        f_min_num = min_num;
    } else if (min_num/1024 < 1024) {
        min_unit = "KB";
        f_min_num = min_num/1024.0;
    } else if (min_num/1024/1024 < 1024) {
        min_unit = "MB";
        f_min_num = min_num/1024.0/1024;
    } else if (min_num/1024/1024/1024 < 1024) {
        min_unit = "GB";
        f_min_num = min_num/1024.0/1024/1024;
    } else {
        min_unit = "TB";
        f_min_num = min_num/1024.0/1024/1024/1024;
    }

    CursorMoveToLeftBeginAndClearAfter();
    if (strlen(name) < max_name) {
        sprintf(format_buff, "%%-%ds[%%-%ds][%1.1f%s/%1.1f%s]\n", max_name, progress_len, f_min_num, min_unit, f_max_num, max_unit);
        printf(format_buff, name, arr);
    } else {
        sprintf(format_buff, "%.*s[%%-%ds][%1.1f%s/%1.1f%s]\n", max_name, name, progress_len, f_min_num, min_unit, f_max_num, max_unit);
        printf(format_buff, arr);
    }
}

void show_net_formate(char *name, int max_name, char *ip, long long tx_speed, long long rx_speed) {

    char *tx_unit, *rx_unit;
    double f_tx_speed, f_rx_speed;
    if (tx_speed<1024) {
        tx_unit = "B";
        f_tx_speed = tx_speed;
    } else if (tx_speed/1024 < 1024) {
        tx_unit = "KB";
        f_tx_speed = tx_speed/1024.0;
    } else if (tx_speed/1024/1024 < 1024) {
        tx_unit = "MB";
        f_tx_speed = tx_speed/1024.0/1024;
    } else if (tx_speed/1024/1024/1024 < 1024) {
        tx_unit = "GB";
        f_tx_speed = tx_speed/1024.0/1024/1024;
    } else {
        tx_unit = "TB";
        f_tx_speed = tx_speed/1024.0/1024/1024/1024;
    }
    if (rx_speed<1024) {
        rx_unit = "B";
        f_rx_speed = rx_speed;
    } else if (rx_speed/1024 < 1024) {
        rx_unit = "KB";
        f_rx_speed = rx_speed/1024.0;
    } else if (rx_speed/1024/1024 < 1024) {
        rx_unit = "MB";
        f_rx_speed = rx_speed/1024.0/1024;
    } else if (rx_speed/1024/1024/1024 < 1024) {
        rx_unit = "GB";
        f_rx_speed = rx_speed/1024.0/1024/1024;
    } else {
        rx_unit = "TB";
        f_rx_speed = rx_speed/1024.0/1024/1024/1024;
    }

    char tx_tmp[50], rx_tmp[50];
        sprintf(tx_tmp, "%.2f%s", f_tx_speed, tx_unit);
        sprintf(rx_tmp, "%.2f%s", f_rx_speed, rx_unit);
    char format_buff[50];
    CursorMoveToLeftBeginAndClearAfter();
    if (strlen(name) < max_name) {
        sprintf(format_buff, "%%-%ds%%-17s%%-%ds%%-%ds\n", max_name, 9, 9);
        printf(format_buff, name, ip, tx_tmp, rx_tmp);
        // sprintf(format_buff, "%%-%ds%%-17s%%-*.2f%s%%-*.2f%s\n\0\0\0\0", max_name, tx_unit, rx_unit);
        // printf(format_buff, name, ip, 9, f_tx_speed, 9, f_rx_speed);
    } else {
        sprintf(format_buff, "%%.*s%%-17s%%-%ds%%-%ds\n", 9, 9);
        printf(format_buff, max_name, name, ip, tx_tmp, rx_tmp);
        // sprintf(format_buff, "%.*s[%%-%ds][%1.2f%%%%]\n\0\0\0\0", max_name, name, progress_len, progress);
        // printf(format_buff, arr);
    }
}

void simple_display() {
    // screen size
    int row, column;
    if (GetWinsize(&row, &column)) {
        printf("get window size fail\n");
    }
    
    // check line num
    int cpu_line = cpu_rate.cpu_num;
    int net_line = 0;
    for (int i=0; i<net_info.net_info_num; i++) {
        if (net_info.ninfo[i].sa_family == AF_INET) {
            net_line++;
        }
    }
    
    int io_chose = 0;
    for (int i=0; i<io_rate.disk_num; i++) {
        if (io_rate.nstatus[i].major_num!=1 && io_rate.nstatus[i].major_num!=7 ) {
            io_chose = i;
            break;
        }
    }
    
    // cpu + 1(mem) + 1(disk) + 1(io) + net+2 
    int total = cpu_line+3+net_line+2;
    if (row < total || column<45) {
        SetColorStyle(FONT_RED);
        printf("please adjust windows row line more than row=%d, column=%d。(r-%d,c-%d)\n", total, 45, row, column);
        return;
    } else {
        SetColorStyle(DEFAULT_MONITOR_SET);
    }
    
    static int once=0;
    if (!once) {
        printf("total = %d\n", total);
        once = 1;
        for (int i=0;i<total;i++) {
            printf("\n");
        }
    }
    for (int i=0;i<total;i++) {
        CursorMoveUpOneRow();
    }

    // 
    #define DATA_SPACE 30
    #define MAX_NAME 7
    for (int i=0; i<cpu_rate.cpu_num; i++) {
        show_cpu_formate(cpu_rate.ninfo[i].name, MAX_NAME, cpu_rate.cpu_usage_rate[i], column-DATA_SPACE, cpu_rate.cpu_temperature);
    }
    show_disk_formate("memory", MAX_NAME, (long long)minfo.mem_total*1024, (long long)(minfo.mem_total-minfo.mem_avalible)*1024, column-DATA_SPACE);
    show_disk_formate("disk", MAX_NAME, (long long)disk_sfs.f_bsize*disk_sfs.f_blocks, (long long)(disk_sfs.f_blocks-disk_sfs.f_bfree)*disk_sfs.f_bsize, column-DATA_SPACE);
    show_cpu_formate("io", MAX_NAME, io_rate.io_usage_rate[io_chose], column-DATA_SPACE, 0);
    CursorMoveToLeftBeginAndClearAfter();
    printf("net :\n");
    CursorMoveToLeftBeginAndClearAfter();
    printf("Interface  Ip               tx/s     rx/s \n");
    for (int i=0; i<net_info.net_info_num; i++) {
        if (net_info.ninfo[i].sa_family == AF_INET) {
            show_net_formate(net_info.ninfo[i].name, 11, net_info.ninfo[i].ip, net_info.ninfo[i].flow_info.tx_speed, net_info.ninfo[i].flow_info.rcv_speed);
        }
    }

    CursorMoveToLeftBeginAndClearAfter();
}

int main() {

    // show_cpu_formate("cpubcadawd", 7, 56.33, 34);
    // show_disk_formate("diskinlkh", 7, 46874525145, 4184965745, 34);
    // printf("Interface  Ip               tx/s     rx/s \n");
    // show_net_formate("wlan0jbljkjkccc", 11, "192.168.5.3", 464674, 485453756);
    // printf("%-*.2f", 20, 20.564);
    printf("%s\n", COMPLATE_MESSAGE);
    if (init() == -1) {
        return -1;
    }
    while (1) {
        reflesh(1000);
        simple_display();
        sleep(1);
    }
    

    FILE *fp = fopen("/sys/class/thermal/thermal_zone0/temp", "r");
    if (!fp) {
        perror("fopen");
        return -1;
    }
    char buff[10];
    char*fg = fgets(buff, sizeof(buff), fp);
    if (fg == NULL) {
        perror("fgets");
        printf("%s\n", buff);
        return -1;
    } else {
        printf("ret = %s\n", buff);
        return 0;
    }

    return 0;
}

